#!/bin/bash
VERSION='2.0'

GNAP_LIBDIR=${GNAP_LIBDIR:-'/usr/lib/gnap'}
source ${GNAP_LIBDIR}/gnap_shared.sh
echo "GNAP overlay tool ${NAME} ${VERSION}"

usage() {
	echo
    echo 'Usage:'
    echo "  ${NAME} -i isoname -o overlay [ options ]"
    echo "  ${NAME} -d hostdisk -r rootdev -o overlay [ options ]"
    echo
    echo 'Common options:'
    echo '  -o overlay    Overlay directory or tbz2 file'
    echo '  -c conf       overlay.conf file to use (if not in overlays)'
    echo '  -g gnap_core  Use specific GNAP core tarball file'
    echo '  -n            Do not use the GNAP castle logo'
    echo '  -f            Force all answers to yes (dangerous!)'
    echo
    echo 'Options for ISO target (create an ISO containing bootable CD):'
    echo '  -i isoname    Customized LiveCD ISO output file name'
    echo
    echo 'Options for disk target (install to a disk plugged in system):'
    echo '  -d hostdisk   Disk to install to, as seen on current host'
    echo '  -r rootdev    Boot device name as seen from target system'
    echo '  -m            Cache filesystem in memory to reduce media wear'
    echo '  -s            Use serial console on ttyS0'
    echo
    echo 'Options for image target (install into a disk image):'
    echo '  -l image      Use existing image file as output'
    echo '                Warning: only one partition is supported!'
    echo '  -L image      Create image file and use it as output'
    echo '  -S size       Size of image file in megabyte'
    echo '  The disk target options also apply, except -d.'
    echo
    echo "Please use man ${NAME} for more details."
}

if [[ "$#" -eq 0 || "${1}" == '-h' ]]; then
	usage
	exit 0
fi

# Default settings
GNAP_NOLOGO=${GNAP_NOLOGO:-0}
GNAP_CREATE=${GNAP_CREATE:-'n'}
GNAP_IMG_SIZE=${GNAP_IMG_SIZE:-15}

# Read options
gbegin 'Checking parameters'

while getopts ':hg:o:c:nfi:d:l:r:ms:S:L:' option; do
	case ${option} in
		h ) usage
			exit 0;;
		g ) GNAP_CORE="${OPTARG}";;
		o ) GNAP_OVERLAYS="${GNAP_OVERLAYS} ${OPTARG}";;
		c ) GNAP_OVERLAY_CONF="${OPTARG}";;
		n ) GNAP_NOLOGO=1;;
		f ) GNAP_FORCEYES=1;;
		i ) GNAP_OUTPUT="${OPTARG}"
			GNAP_TYPE='iso';;
		d ) GNAP_OUTPUT="${OPTARG}"
			GNAP_TYPE='disk';;
		l ) GNAP_OUTPUT="${OPTARG}"
			GNAP_TYPE='image'
			GNAP_CREATE='n';;
		L ) GNAP_OUTPUT="${OPTARG}"
			GNAP_TYPE='image'
			GNAP_CREATE='y';;
		S ) GNAP_IMG_SIZE="${OPTARG}";;
		r ) GNAP_TARGETROOT="${OPTARG}";;
		m ) GNAP_CACHE='docache ';;
		s ) GNAP_SERIAL="console=ttyS0,${OPTARG}n81"
			GNAP_BAUDRATE="${OPTARG}";;
		* ) gtest 1 'Specified options are incomplete or unknown!';;
	esac
done

# Target type (-i or -d) is needed
test -n "${GNAP_TYPE}"
gtest continued $? 'Please specify a target (-i or -d option)'

# Core file is required
test -f "${GNAP_CORE}"
gtest continued $? 'Please specify a valid GNAP core file (-g option)'

case "${GNAP_TYPE}" in
	disk)
		# if disk type, doublecheck everything is ok
		PARENTDEV="${GNAP_OUTPUT:0:$((${#GNAP_OUTPUT}-1))}"
		test -b "${PARENTDEV}"
		gtest continued $? "${PARENTDEV} device does not exist on this system"
		test -b "${GNAP_OUTPUT}"
		gtest continued $? "${GNAP_OUTPUT} partition does not exist on this system"
	;;
	image)
		if [[ "${GNAP_CREATE}" != 'y' ]]; then
			# Check whether image file exists
			test -f "${GNAP_OUTPUT}"
			gtest continued $? "Image file ${GNAP_OUTPUT} does not exist."
		fi
	;;
esac

# At least one overlay is required
test -n "${GNAP_OVERLAYS}${GNAP_OVERLAY_CONF}"
gtest $? 'Please specify at least an overlay (-o) or config file (-c)'

# Warning for disk type targets
if [[ "${GNAP_TYPE}" == 'disk' ]]; then
	gwarn 'Warning : you have selected disk install'
	gwarn "Make sure you are root or have full access to ${GNAP_OUTPUT}"
	gwarn "${PARENTDEV} must have an MBR installed, run:"
	gwarn "${W}dd if=${GNAP_MBR} of=${PARENTDEV} bs=512 count=1${N} if needed"
	gwarn "${GNAP_OUTPUT} must contain an active partition:"
	gwarn " use ${W}fdisk ${PARENTDEV}${N} if needed"
	gwarn "Current data on ${GNAP_OUTPUT} will be ${B}destroyed${N}!"
	gconfirm 'Are you sure you want to continue ?'
fi

# Common actions
gbegin "Expanding ${GNAP_CORE} core"
TEMPDIR=$(mktemp -d -t gnap_overlay.XXXXXX)
gtest continued $? 'Failed to create temporary directory'
TEMPCOREDIR="${TEMPDIR}/core"
gmkdir "${TEMPCOREDIR}"
tar x -C "${TEMPCOREDIR}" -f "${GNAP_CORE}"
gtest $? 'Failed to extract core'

gbegin 'Preparing overlay'
TEMPOVERDIR="${TEMPDIR}/overlay"
gmkdir "${TEMPOVERDIR}"

if [[ -n "${GNAP_BAUDRATE}" ]]; then
	gbegin 'Adding baudrate for serial console'
	gmkdir -p "${TEMPOVERDIR}/etc/gnap"
	echo -n "${GNAP_BAUDRATE}" > "${TEMPOVERDIR}/etc/gnap/baudrate"
	gtest $? 'Failed to create /etc/gnap/baudrate'
fi
for overlay in ${GNAP_OVERLAYS} ; do
	if [[ -d "${overlay}" ]]; then
		gbegin "Adding ${overlay} (directory overlay)"
		cp -rp "${overlay}"/* "${TEMPOVERDIR}"
		gtest $? "Failed to copy ${overlay}"
	else
		gbegin "Adding ${overlay} (conflet file)"
		tar jxf "${overlay}" -C "${TEMPOVERDIR}" 2>/dev/null
		gtest $? "${overlay} is not a valid conflet file (tbz2 format)"
	fi
done
if [[ -n "${GNAP_OVERLAY_CONF}" ]]; then
	gbegin "Adding ${GNAP_OVERLAY_CONF} (overlay.conf file)"
	if [[ ! -d "${TEMPOVERDIR}/etc" ]]; then
		gmkdir "${TEMPOVERDIR}/etc"
	fi
	cp "${GNAP_OVERLAY_CONF}" "${TEMPOVERDIR}/etc/overlay.conf"
	gtest $? "Failed to copy ${GNAP_OVERLAY_CONF}"
fi
gbegin 'Creating overlay tarball'
test -f "${TEMPOVERDIR}/etc/overlay.conf"
gtest continued $? 'Specified overlays do not contain any etc/overlay.conf'
tar zc -C "${TEMPOVERDIR}" --exclude CVS --exclude .svn \
	-f "${TEMPCOREDIR}/overlay.tgz" .
gtest $? 'Failed to create overlay tarball'

DATE=$(date --utc)
if [[ "${GNAP_NOLOGO}" -eq 1 ]]; then
	echo "GNAP ${VERSION}" > "${TEMPCOREDIR}/isolinux/boot.msg"
fi
if [[ -n "${GNAP_OVERLAYS}" ]]; then
	echo "Overlaid with ${GNAP_OVERLAYS} on ${DATE}" \
		>> "${TEMPCOREDIR}/isolinux/boot.msg"
fi

# Target specific actions
if [[ "${GNAP_TYPE}" == 'iso' ]]; then
	if [[ -f "${GNAP_OUTPUT}" ]]; then
		gconfirm "File ${GNAP_OUTPUT} already exists, overwrite?"
	fi
	rm "${TEMPCOREDIR}/syslinux.cfg"
	gbegin "Building ${GNAP_OUTPUT} ISO file"
	mkisofs -quiet -J -r -l -x "${TEMPCOREDIR}/.." -o "${GNAP_OUTPUT}" \
		-b isolinux/isolinux.bin -c isolinux/boot.cat \
		-no-emul-boot -boot-load-size 4 -boot-info-table "${TEMPCOREDIR}"
	gtest $?

else
	if [[ "${GNAP_TYPE}" == 'image' ]]; then
		gbegin 'Looking for free loop device'
		LOOP=''
		for i in /dev/loop/?* /dev/loop?*; do
			if [[ -e "${i}" ]]; then
				if ! losetup "${i}" >/dev/null 2>&1
				then
					LOOP="${i}"
					break
				fi
			fi
		done
		test -n "${LOOP}"
		gtest $? 'Unable to find free loop device'

		ginfo "Using loop device ${LOOP}"

		if [[ "${GNAP_CREATE}"  == y ]]; then
			if [[ -f "${GNAP_OUTPUT}" ]]; then
				gconfirm "File ${GNAP_OUTPUT} already exists, overwrite?"
			fi

			gbegin 'Creating image file'
			# 1048576 = 1 MiB
			dd if=/dev/zero of="${GNAP_OUTPUT}" bs=1048576 count="${GNAP_IMG_SIZE}" \
				>/dev/null 2>&1
			gtest $?

			gbegin 'Creating partition table'
			# Create one partition of the full size
			echo '0;;6;*' | sfdisk -D -H 64 -S 32 "${GNAP_OUTPUT}" >/dev/null 2>&1
			gtest $?
		fi

		gbegin 'Reading Cylinder/Heads/Sectors'
		CHS=$(sfdisk -G "${GNAP_OUTPUT}" 2>/dev/null)
		gtest $?

		set -- ${CHS/*:/}

		IMG_CYLINDERS="${1}"
		IMG_HEADS="${3}"
		IMG_SECTORS="${5}"

		offset=$[${IMG_SECTORS} * 512]

		ginfo "Offset is ${offset}"

		gbegin "Mounting ${GNAP_OUTPUT} to ${LOOP}"
		losetup -o "${offset}" "${LOOP}" "${GNAP_OUTPUT}"
		gtest $?

		ORIG_OUTPUT="${GNAP_OUTPUT}"
		GNAP_OUTPUT="${LOOP}"
	fi

	gbegin "Formatting ${GNAP_OUTPUT}"
	mkfs.msdos "${GNAP_OUTPUT}" > /dev/null 2>&1
	gtest $?

	gbegin "Mounting ${GNAP_OUTPUT}"
	TEMPMOUNTDIR="${TEMPDIR}/mount"
	gmkdir "${TEMPMOUNTDIR}"
	mount -t msdos "${GNAP_OUTPUT}" "${TEMPMOUNTDIR}"
	gtest $?

	gbegin 'Copying files'
	cp ${TEMPCOREDIR}/syslinux.cfg			${TEMPMOUNTDIR}/			&&\
	cp ${TEMPCOREDIR}/isolinux/gentoo.igz	${TEMPMOUNTDIR}/			&&\
	cp ${TEMPCOREDIR}/isolinux/gentoo		${TEMPMOUNTDIR}/			&&\
	cp ${TEMPCOREDIR}/isolinux/*.msg		${TEMPMOUNTDIR}/			&&\
	cp ${TEMPCOREDIR}/livecd				${TEMPMOUNTDIR}/			&&\
	cp ${TEMPCOREDIR}/overlay.tgz			${TEMPMOUNTDIR}/			&&\
	cp ${TEMPCOREDIR}/image.squashfs		${TEMPMOUNTDIR}/image.sfs	&&\
	sed -i \
		"s:cdroot:cdroot=/dev/${GNAP_TARGETROOT} ${GNAP_CACHE}${GNAP_SERIAL}:" \
		"${TEMPMOUNTDIR}/syslinux.cfg"
	gtest $?

	gbegin "Unmounting ${GNAP_OUTPUT}"
	umount "${TEMPMOUNTDIR}"
	gtest $?

	# Is autocleaned so maybe not useful
	if [[ "${GNAP_TYPE}" == 'image' ]]; then
		losetup -d "${LOOP}"
		LOOP=
	fi

	export MTOOLS_SKIP_CHECK=1
	case "${GNAP_TYPE}" in
		disk)
			gbegin 'Syslinuxing'
			syslinux "${GNAP_OUTPUT}"
			gtest $?
		;;
		image)
			gbegin 'Preparing disk for boot'
			syslinux -o "${offset}" "${ORIG_OUTPUT}" && \
			dd if="${GNAP_MBR}" of="${ORIG_OUTPUT}" bs=512 count=1 \
				conv=notrunc >/dev/null 2>&1
			gtest $?
		;;
	esac
fi

# Successful finish
cleanup
echo 'Overlay successful!'
exit 0
